package org.opengeoingest.tufts.Layer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.opengeoingest.tufts.Layer.BaseGeoParser.Access;
import org.opengeoingest.tufts.Layer.BaseGeoParser.Key;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * the OGP Solr record evolves over time, this class has code to make adjustments as needed
 * It reads in a Solr file, modifies the XML and writes it back out.
 * For example, the function updateLcoationField changes the value of the Solr Location field.
 * Since this field now has a JSON hashtable of services this class is needed to update a bunch
 * of old files.    
 * @author smcdon08
 *
 */
public class SolrFileAdjuster
{
	/**
	 * create new file similar to input file but with updated Location field
	 * as of OGP release 1.1, the Location field in the Solr record is a hashtable of server urls
	 * 
	 * for details see http://code.google.com/p/opengeoportal/wiki/ConfigFileChanges
	 * @param fileName
	 * @param outputFile
	 */
	private void updateLocationField(File fileName, File outputFile)
	{
		InputStream inputStream = null;
		OutputStream outputStream = null;
		try
		{
			inputStream = new FileInputStream(fileName);
			outputStream = new FileOutputStream(outputFile);
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
					.newInstance();
			documentBuilderFactory.setValidating(false); // dtd isn't available
			documentBuilderFactory
					.setFeature(
							"http://apache.org/xml/features/nonvalidating/load-external-dtd",
							false);
			DocumentBuilder documentBuilder = documentBuilderFactory
					.newDocumentBuilder();
			Document document = documentBuilder.parse(inputStream);
			
			// modify document
			// pull required fields out of Solr info and compute new Location value
			String institution = getValue(document, "Institution");
			String dataType = getValue(document, Key.DataType.toString());
			String access$ =  getValue(document, Key.Access.toString());
			Access access = Access.valueOf(access$);
			String updatedLocation = ToSolr.getLocation(institution, access, dataType);
			Node locationNode = getNode(document, "Location");

			locationNode.setTextContent(updatedLocation);
			
			// now save the changed DOM/document out to disk
			TransformerFactory tFactory = TransformerFactory.newInstance();
			Transformer transformer = tFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			DOMSource source = new DOMSource(document);
			StreamResult result = new StreamResult(outputStream);
			transformer.transform(source, result);
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (ParserConfigurationException e)
		{
			e.printStackTrace();
		}
		catch (SAXException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		catch (TransformerConfigurationException e)
		{
			e.printStackTrace();
		}
		catch (TransformerException e)
		{
			e.printStackTrace();
		}
		finally
		{
			closeInput(inputStream);
			closeOutput(outputStream);
		}

	}
	
	/**
	 * loop over all the "field" tags looking for one whose name is desiredAttribute (e.g., DataType)
	 * when found, return the "field" parent node  
	 * 
	 * @param document
	 * @param desiredAttribute
	 * @return
	 */
	private static Node getNode(Document document, String desiredAttribute)
	{
		NodeList nodes = document.getElementsByTagName("field");
		for (int i = 0 ; i < nodes.getLength() ; i++)
		{
			Node node = nodes.item(i);
			NamedNodeMap attributes = node.getAttributes();
			Node nameAttributeNode = attributes.getNamedItem("name");
			String nameAttribute = nameAttributeNode.getNodeValue();
			if (nameAttribute.equals(desiredAttribute))
				return node;
		}
		System.out.println("in getNode, never found " + desiredAttribute);
		return null;
	}
	
	/**
	 * get the field node for the desiredAttribute and return the value of a "field" element (e.g., Raster)
	 * @param document
	 * @param desiredAttribute
	 * @return
	 */
	private static String getValue(Document document, String desiredAttribute)
	{
		Node node = getNode(document, desiredAttribute);
		String value = node.getTextContent();
		return value;
	}
	
	private static void closeInput(InputStream inputStream)
	{
		if (inputStream != null)
		{
			try
			{
				inputStream.close();
			}
			catch (IOException e)
			{
				;
			}
		}
	}

	private static void closeOutput(OutputStream outputStream)
	{
		if (outputStream != null)
		{
			try
			{
				outputStream.close();
			}
			catch (IOException e)
			{
				;
			}
		}
	}

	/**
	 * loop over all metadata files in the hard-coded directories and process file
	 * @param args
	 */
	public static void main(String[] args)
	{
		File outputDirectory = new File("/Users/smcdon08/tmp/OpenGeoPortal/BerkeleySolrLocation/");
		
		System.out.println("top of SolrFileAdjuster");
		SolrFileAdjuster adjuster = new SolrFileAdjuster();
		
		String[] directories = { "/Users/smcdon08/tmp/OpenGeoPortal/BerkeleySolr/AllSolrRecords"};

		for (String tempDirectory : directories)
		{
			File currentDirectory = new File(tempDirectory);
			File[] solrFiles = currentDirectory.listFiles();
			// loop over all the files in the directory and process the xml
			for (File currentSolrFile : solrFiles)
			{
				String filename = currentSolrFile.getName();
				if (filename.endsWith(".xml"))
				{
					File outputFile = new File(outputDirectory, filename);
					System.out.println("processing file " + currentSolrFile);
					adjuster.updateLocationField(currentSolrFile, outputFile);
				}

			}
		}
		// all done processing files, create report for user
		System.out.println("end of report");
		
	}
}
